/* Created on Sep 29, 2010 */
package org.tdwg.codeblitz.service;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

import org.tdwg.codeblitz.model.MediaFile;
import org.tdwg.codeblitz.model.Point;
import org.tdwg.codeblitz.model.Walk;

import com.google.gdata.client.GoogleService;
import com.google.gdata.client.Service.GDataRequest;
import com.google.gdata.client.Service.GDataRequest.RequestType;
import com.google.gdata.util.ContentType;

/**
 * @author Ian Cottingham
 * 
 */
@Path("/query")
public class QueryService {

	private static final String SERVICE_URL = "http://tables.googlelabs.com/api/query";

	private final Logger LOG = Logger.getLogger(QueryService.class
			.getCanonicalName());
	
	@GET
	@Path("/walks")
	@Produces("application/json")
	public List<Walk> queryWalks() {
		return new Constructor<Walk>().constructFromGDataRequest(
				executeQuery("select GUID,Name,Description,Walker,Date from "
						+ Walk.TABLE_ID), Walk.class);
	}

	@GET
	@Path("/walk/{guid}")
	@Produces("application/json")
	public Walk queryWalkForGuid(@PathParam("guid") String guid) {

		List<Walk> walks = new Constructor<Walk>().constructFromGDataRequest(
				executeQuery("select GUID,Name,Description,Walker,Date from "
						+ Walk.TABLE_ID + " where GUID = " + guid), Walk.class);

		return (walks.size() == 1) ? walks.get(0) : new Walk();
	}

	@GET
	@Path("/points/{guid}")
	@Produces("application/json")
	public List<Point> queryPoinsForWalk(@PathParam("guid") String walkGuid) {
		return new Constructor<Point>().constructFromGDataRequest(
				executeQuery("select GUID,Location,Date,Elevation from "+ Point.TABLE_ID + " where Walk_REF = " + walkGuid+" order by Date desc"),
				Point.class);
	}

	@GET
	@Path("/files/{guid}")
	@Produces("application/json")
	public List<MediaFile> queryMediaFilesForWalk(
			@PathParam("guid") String walkGuid) {
		return new Constructor<MediaFile>().constructFromGDataRequest(
				executeQuery("select GUID,URI,Date,Location,Host,Specimen,Comments,ROWID from " + MediaFile.TABLE_ID
						+ " where Walk_REF = " + walkGuid), MediaFile.class);
	}
	
	@GET
	@Path("/file/{guid}")
	@Produces("audio/mpeg")
	public Response queryMediaFileForGuid(
			@PathParam("guid") String mediaFileGuid
	) {
		List<MediaFile> mediaFiles = new Constructor<MediaFile>().constructFromGDataRequest(
				executeQuery("select GUID,URI,Date,Location,Host,Specimen,Comments,ROWID from " + MediaFile.TABLE_ID
						+ " where GUID = " + mediaFileGuid), MediaFile.class);

		try {
			File file = new File(mediaFiles.get(0).getUri());
			FileInputStream fileInputStream = new FileInputStream(mediaFiles.get(0).getUri());
			byte[] fileBytes = new byte[(int)file.length()];
			fileInputStream.read(fileBytes);
			return Response.ok(fileBytes).build();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	private GDataRequest executeQuery(String query) {
		try {
			GoogleService service = new GoogleService("fusiontables",
					"org.tdwg.codeblitz.GPSVoiceTracker");

			URL url = new URL(SERVICE_URL + "?sql="
					+ URLEncoder.encode(query, "UTF-8"));
			GDataRequest request = service.getRequestFactory().getRequest(
					RequestType.QUERY, url, ContentType.TEXT_PLAIN);

			request.execute();
			return request;
		} catch (Exception e) {
			LOG.log(Level.SEVERE,
					"The fusion tables query could not be exeuted", e);
			RuntimeException re = new RuntimeException(
					"Could not execute the fusion tables query");
			re.initCause(e);
			throw re;
		}
	}

	private class Constructor<T> {

		protected List<T> constructFromGDataRequest(GDataRequest request,
				Class<T> type) {
			List<T> results = new ArrayList<T>();

			try {
				BufferedReader reader = new BufferedReader(
						new InputStreamReader(request.getResponseStream()));
				String line = reader.readLine(); // parse off the header line
				
				while ((line = reader.readLine()) != null) {
					results.add(type.getConstructor(
							new Class[] { String.class }).newInstance(line+"\n"));
				}
			} catch (Exception e) {
				LOG.log(Level.SEVERE,
						"The fusion tables response could not be parsed", e);
				RuntimeException re = new RuntimeException(
						"Could not parse the fusion tables response");
				re.initCause(e);
				throw re;
			}

			return results;
		}
	}
}
